/**
 * Base class handling incoming messages
 */
var EventHandler = {
  /**
   * Wrapper for incoming message
   * @param event object containing data from server, used to parse data to JSON object
   * @param token token with event type
   */
  BristleIncomingMessage : function(event, token) {
    this.eventName = token.type;
    this.params = Bristle.parseJSON(event.data)
  },

    /**
   * Wrapper for callback incoming message
   * @param event object containing data from server, used to parse data to JSON object
   * @param token token with event type
   */
  BristleCallbackMessage : function(event, token) {
    this.eventName = token.type;
    this.actionId =  "utid" + token.utid;
    this.exceptionType = token[Bristle.EXCEPTION_TYPE];
    this.exceptionValue = token[Bristle.EXCEPTION_VALUE] ? token[Bristle.EXCEPTION_VALUE] : {};
    this.exceptionValue.getExceptionType = function(){
      return token[Bristle.EXCEPTION_TYPE];
    },
    this.hasException = function(){
      return this.exceptionType != undefined;
    };
    this.exceptionValue.isValidationException = function(){
      return this.getExceptionType() == "ValidationException";
    };
    this.params = Bristle.parseJSON(event.data);
  },

  /**
   * Main handler class for all incoming messages
   * Handles callback messages and messages send by server
   */
  BristleEventHandler : function() {
    this.setConnector = function(connector) {
      this.connectorInstance = connector;
      this.callbacks = connector.fRequestCallbacks;
    };

    /**
     * method handling all incoming messages from server
     * handles callback functions and messages send directly from server
     */
    this.handleIncomingMessage = function(event, token) {
      if (this.isCallback(token)) {
        this.handleCallback(new EventHandler.BristleCallbackMessage(event, token));
      } else {
        this.handleMessage(new EventHandler.BristleIncomingMessage(event, token));
      }
    };

    /**
     * method handling messages send from server,
     * @param incomingMessage BristleIncomingMessage - data already parsed to JSON
     */
    this.handleMessage = function (incomingMessage) {
      try {
        if (incomingMessage.params.ns == this.connectorInstance.NS) {
          Bristle.log("EVENT(" + incomingMessage.eventName + "): " + Bristle.objectToString(incomingMessage.params) + "<br>");
          EventHandler.events[incomingMessage.eventName](incomingMessage.params);
        }
      } catch(typeError) {
        throw new EventNotHandledError(typeError);
      }
    };

    /**
     * Method used by callback mechanism
     * Called when invoking event on server failed
     * @param token
     * @param onFailure
     */
    this.callFailureCallback = function(message, onFailure) {
      var exceptionValue = message.exceptionValue;
      Bristle.log("CALLBACK EXCEPTION (" + exceptionValue.getExceptionType() + "): " + Bristle.objectToString(exceptionValue) + "<br>");
      onFailure.call(this, exceptionValue);
    };

    this.handleCallback = function(message) {
      var actionCallback = this.callbacks[ message.actionId ];
      if (actionCallback) {
        if (message.hasException()) {
          this.callFailureCallback(message, actionCallback.callback.onFailure);
        } else {
          actionCallback.callback.onSuccess.call(this, message.params);
          Bristle.log("EVENT-CALLBACK(" + message.eventName + "): " + Bristle.objectToString(message.params) + "<br>");
        }
        delete this.callbacks[ message.actionId ];
        return true;
      } else {
        return false;
      }
    };

    this.isCallback = function(token) {
      var actionId = "utid" + token.utid;
      var actionCallback = this.callbacks[ actionId ];
      return actionCallback != undefined;
    };
  },

  /**
   * List of events
   */
  events : {
  },

  /**
   * Add new handler to given event name.
   * If handler is already added Error is thrown.
   * Use EventHandler.attach to override currently added event
   * @param eventName
   * @param handler
   */
  add : function(eventName, handler) {
    if (typeof this.events[eventName] !== 'undefined') {
      throw new Error("event with such name already added, use atach event handler to override current event")
    }
    this.events[eventName] = handler;
  },

  /**
   * Add new or overrides current handler to given event name.
   * Use this function to add handlers for event
   * @param eventName
   * @param handler
   */
  attach : function(eventName, handler) {
    this.events[eventName] = handler;
  }

};



